import * as d3 from "d3";

class DrawByD3 {
    constructor(
        className,
        w,
        h,
        option = {
            scheme: "schemeCategory10", // 详细主题列表查阅d3.js color
            mark: {
                color: "white",
                border: true,
                fontSize: 11,
                render: undefined,
            },
            tip: true,
        }
    ) {
        this.svg = d3
            .select("." + className)
            .append("svg")
            .attr("width", w)
            .attr("height", h)
            // 对 svg 宽高进行移动, 以使其中心点对准需要放置的位置
            .attr("transform", `translate(${-w / 2}, ${-h / 2})`)
            .style("overflow", "visible");

        this.w = w;
        this.h = h;
        this.option = option;
    }

    midAngle(d) {
        return d.startAngle + (d.endAngle - d.startAngle) / 2;
    }

    /**
     * @description: 饼图
     * @param {Number[]} dataset 数据
     * @param {[]} fields 字段名
     * @param {Boolean} isRing 是否有内环
     * @return {*}
     */
    pie(dataset, fields, isRing) {
        const { svg, w, h } = this;
        const outerRadius = w / 2; // 饼图半径
        const innerRadius = isRing ? w / 4 : 0; // 内环半径(绘制 pie 时设置 0)
        // d3 方法
        const arc = d3.arc().innerRadius(innerRadius).outerRadius(outerRadius);
        const d3pie = d3.pie();

        // Easy colors accessible via a 10-step ordinal scale
        // 模式使用主题 schemeCategory10
        const color = d3.scaleOrdinal(d3[this.option.scheme]);

        // 设置arc
        const arcs = svg
            .selectAll("g.arc")
            .data(d3pie(dataset))
            .enter()
            .append("g")
            .attr("class", "arc")
            // 通过 transform ,省得定义 起始点
            .attr(
                "transform",
                "translate(" + outerRadius + "," + outerRadius + ")"
            );

        // 绘制路径
        arcs.append("path")
            .attr("fill", (d, i) => color(i))
            .transition()
            .attr("d", arc);

        // 添加注记
        // arcs.append("text")
        //     .attr("class", `chart-mark-${this.id}`)
        //     .attr("transform", (d) => `translate(${arc.centroid(d)})`)
        //     .attr("font-size", "11px")
        //     .attr("fill", "white")
        //     .attr("text-anchor", "middle")
        //     .attr("stroke", "black") // 边框颜色
        //     .attr("stroke-width", "1.0px") // 边框宽度
        //     .attr("stroke-linejoin", "round") // 边框转角样式
        //     .attr("paint-order", "stroke") // 确保边框在填充下方
        //     .text((d, i) => `${fields[i]}\n${d.value} `);
        // 添加文字标注
        if (this.option.mark) {
            const outerArc = d3
                .arc()
                .innerRadius(outerRadius * 0.9)
                .outerRadius(outerRadius * 0.9);
            // 添加引导线
            // arcs.append("polyline")
            //     .attr("class", "label-line")
            //     .attr("points", (d) => {
            //         const pos = outerArc.centroid(d);
            //         pos[0] = radius * 0.95 * (midAngle(d) < Math.PI ? 1 : -1);
            //         return [arc.centroid(d), outerArc.centroid(d), pos];
            //     });
            arcs.append("text")
                .attr("font-size", `${this.option.mark.fontSize}px`)
                .attr("fill", this.option.mark.color)
                .attr("text-anchor", "middle")
                .attr("stroke", (d, i) =>
                    this.option.mark.border ? color(i) : "transparent"
                )
                .attr("stroke-width", "2px")
                .attr("stroke-linejoin", "round")
                .attr("paint-order", "stroke") // 确保边框在填充下方
                .attr("dy", ".35em")
                .attr("transform", (d) => {
                    const pos = outerArc.centroid(d);
                    pos[0] =
                        outerRadius *
                        0.5 *
                        (this.midAngle(d) < Math.PI ? 1 : -1);
                    return `translate(${pos})`;
                })
                .style("text-anchor", (d) =>
                    this.midAngle(d) < Math.PI ? "start" : "end"
                )
                .text((d, i) => `${fields[i]}\n${d.value} `);
        }

        if (this.option.tip) {
            this.svg
                .append("title") // 添加title元素作为tooltip
                .text(dataset.map((d, i) => `${fields[i]}:${d} `).join("\n")); // 设置提示内容
        }
    }

    /**
     * @description: 圆环图
     * @param {Number[]} dataset 数据
     * @param {[]} fields 字段名
     * @return {*}
     */
    doughnut(dataset, fields) {
        this.pie(dataset, fields, true);
    }

    /**
     * @description: 柱形图
     * @param {Number[]} dataset 数据
     * @param {[]} fields 字段名
     * @return {*}
     */
    bar(dataset, fields) {
        const { svg, w, h } = this;
        // 模式使用主题 schemeCategory10
        // const color = d3.scaleOrdinal(d3[this.option.scheme]);
        const color = d3.scaleOrdinal(d3.schemeCategory10);

        const padding = 20;
        // 比例尺
        const xScale = d3
            .scaleBand()
            .domain(d3.range(dataset.length))
            .rangeRound([0, w])
            .paddingInner(0.2);

        // 比例尺
        const yScale = d3
            .scaleLinear()
            .domain([0, d3.max(dataset)])
            .range([padding, h - padding]);

        // 设置arc
        const bars = svg
            .selectAll("g.bar")
            .data(dataset)
            .enter()
            .append("g")
            .attr("class", "bar");

        bars.append("rect")
            .attr("x", (d, i) => xScale(i)) // x 定位
            .attr("y", (d) => h - yScale(d)) // y 定位
            .attr("width", xScale.bandwidth()) // 宽度
            .attr("fill", (d, i) => color(i)) // 色彩
            .transition()
            .attr("height", (d) => yScale(d)); // 高度

        // 添加注记
        if (this.option.mark) {
            bars.append("text")
                .attr("font-size", `${this.option.mark.fontSize}px`)
                .attr("fill", this.option.mark.color)
                .attr("text-anchor", "middle")
                .attr("stroke", (d, i) =>
                    this.option.mark.border ? color(i) : "transparent"
                )
                .attr("stroke-width", "2px")
                .attr("stroke-linejoin", "round")
                .attr("paint-order", "stroke") // 确保边框在填充下方
                .attr("x", (d, i) => xScale.bandwidth() / 2)
                .attr("y", (d) => -5)
                .attr(
                    "transform",
                    (d, i) => `translate(${xScale(i)}, ${h - yScale(d)})`
                )
                .attr("text-anchor", "middle")
                .text((d) => d);
        }

        if (this.option.tip) {
            this.svg
                .append("title") // 添加title元素作为tooltip
                .text(dataset.map((d, i) => `${fields[i]}:${d} `).join("\n")); // 设置提示内容
        }
        // bars.append("text")
        //     .attr("x", (d, i) => xScale.bandwidth() / 2)
        //     .attr("y", (d) => -5)
        //     .attr(
        //         "transform",
        //         (d, i) => `translate(${xScale(i)}, ${h - yScale(d)})`
        //     )
        //     .text((d) => d)
        //     .attr("font-size", "11px")
        //     .attr("fill", "white")
        //     .attr("stroke", "black")
        //     .attr("stroke-width", "1px")
        //     .attr("text-anchor", "middle");
    }
}

export default DrawByD3;
export { DrawByD3 };
